package edu.princeton.cogsci.wn;

import java.util.*;

/** This class encapsulates a hierarchical data structure that is specialized
 *  to hold the results of a WordNet search. The abstract base class that
 *  specifies the functionality of a search is <CODE>SearchMacro</CODE>.
 *
 *  @see SearchMacro
 *  @see SearchParameters
 */
public class SearchResults
{
  /** The root of the data structure. */
  public Node root;
  
  /** The name of the search that generated this object. */
  private String searchName;
  
  /** Creates a <CODE>SearchResults</CODE> object with <CODE>sp</CODE> in the
   *  <CODE>data</CODE> field of the root node.
   */
  public SearchResults( SearchParameters sp )
  {
    root = new Node( sp, true );
  }
  
  /** Returns the name of the search that generated this object. */
  public String getSearch( )
  {
    return searchName;
  }
  
  /** Sets the name of the search that generated this object. */
  public void setSearch( String searchName )
  {
    this.searchName = searchName;
  }
  
  /** Returns a string representation of this object, namely, the name of the
   *  search that generated it plus the string representation of the data
   *  structure itself.
   */
  public String toString( )
  {
    return searchName + "\n" + root.toString( "  " );
  }
  
  /** This class represents one node in a hierarchical data structure that is
   *  specialized to hold the results of a WordNet search.
   */
  public static class Node
  {
    /** The data contained by this node. */
    private Object data;
    
    /** Whether this node's children should be displayed. */
    private boolean isExpanded = true;
    
    /** This node's children nodes. */
    private Vector children = new Vector( );
    
    /** Creates an empty node. */
    public Node( ) { }
    
    /** Creates a node with <CODE>data</CODE> contained by it and
     *  <CODE>isExpanded</CODE> determining whether its children should be
     *  displayed.
     */
    public Node( Object data, boolean isExpanded )
    {
      setData( data );
      setExpanded( isExpanded );
    }
    
    /** Returns a string representation of the subtree rooted by this node. */
    public String toString( )
    {
      return toString( "" );
    }
    
    /** Returns a string representation of the subtree rooted by this node,
     *  with <CODE>indent</CODE> prepended to each line.
     */
    public String toString( String indent )
    {
      String results = indent + data.toString( ) + "/" + isExpanded + "\n";
      Iterator i = getChildrenIterator( );
      while ( i.hasNext( ) )
        results += ( ( Node )i.next( ) ).toString( indent + "  " );
      return results;
    }
    
    /** Sets the data contained by this node. */    
    public void setData( Object data )
    {
      this.data = data;
    }
    
    /** Returns the data contained by this node. */
    public Object getData( )
    {
      return data;
    }
    
    /** Sets whether this node's children should be displayed. */
    public void setExpanded( boolean isExpanded )
    {
      this.isExpanded = isExpanded;
    }
    
    /** Returns whether this node's children should be displayed. */
    public boolean isExpanded( )
    {
      return isExpanded;
    }
    
    /** Adds a child to the end of this node's list of children. */
    public void addChild( Node child )
    {
      children.add( child );
    }
    
    /** Creates a child and adds it to the end of this node's list of
     *  children.
     */
    public void addChild( Object data, boolean isExpanded )
    {
      addChild( new Node( data, isExpanded ) );
    }
    
    /** Removes <CODE>child</CODE> from this node's list of children. Does
     *  nothing if <CODE>child</CODE> is not in the list.
     */
    public void removeChild( Node child )
    {
      children.remove( child );
    }
    
    /** Removes the child at index <CODE>i</CODE> in this node's list of
     *  children. Throws <CODE>IndexOutOfBoundsException</CODE> if
     *  <CODE>( i < 0 ) || ( i >= getChildCount( ) )</CODE>.
     */
    public void removeChildAt( int i )
    {
      children.remove( i );
    }
    
    /** Returns the count of this node's children. */
    public int getChildCount( )
    {
      return children.size( );
    }
    
    /** Returns the child at index <CODE>i</CODE> in this node's list of
     *  children. Throws <CODE>IndexOutOfBoundsException</CODE> if
     *  <CODE>( i < 0 ) || ( i >= getChildCount( ) )</CODE>.
     */
    public Node getChildAt( int i )
    {
      return ( Node )children.get( i );
    }
    
    /** Returns the last child in this node's list of children. */
    public Node getLastChild( )
    {
      return getChildAt( getChildCount( ) - 1 );
    }
    
    /** Returns an iterator over this node's children. */
    public Iterator getChildrenIterator( )
    {
      return children.iterator( );
    }
  }
}
